import copy
import random
import time

from twisted.internet import reactor
from twisted.internet import defer
from twisted.web import server, resource, util
from twisted.protocols.http import datetimeToLogString
from twisted.protocols.http import HTTPFactory
from twisted.cred import portal, checkers, credentials
from twisted.cred import error, credentials
from zope import interface

from nevow import rend
from nevow import appserver
from nevow import guard
from nevow import inevow
from nevow import context
from nevow import compy
import nevow.loaders


import activist.web.resource
from activist.DataStore import DataStore
from activist.Config import Config
from activist.Users import Users


class ResourceUserWrapper:
    interface.implements(inevow.IResource)

    def __init__(self,resource,user):
        self.resource = resource
        self.user = user
    
    def locateChild(self,context,path):
        (resource,postpath) = self.resource.locateChild(context,path)
        resource.activist_user = self.user
        return resource,postpath


class ActivistRealm:
    interface.implements(portal.IRealm)
    resource = None

    def __init__(self,resource):
        print "ActivistRealm: go __init__ with resource:",resource
        self.resource = resource
        self.users = 0
        
    def noLogout(self):
        return None
    def requestAvatar(self, avatarId, mind, *interfaces):
        for iface in interfaces:
            if iface is inevow.IResource:
                # do web stuff
                if avatarId is checkers.ANONYMOUS:
                    print "anonymous login"
                    return (inevow.IResource, self.resource, self.noLogout)
                else:
                    mind._person = DataStore[avatarId]
                    print "LOGIN:",mind._person
                    mind.realm = self
                    self.users = self.users + 1

                return (inevow.IResource, self.resource, self.logout)
            
        raise NotImplementedError("Can't support that interface.")

    def logout(self):
        self.users = self.users - 1

class ActivistMind(object):
    lastPath = None
    object = None
    
    def __init__(self, request, creds):
        self._person = None
                                        # will be set up later by ActivistRealm
        self.credentials = creds
        self.showcomments = []
        self.data = {}
        self.options = {
            'summary-comments': False,
            'show-calendar': True
            }

    def __getitem__(self,key):
        try:
            return self.data[key]
        except:
            item = key._makeData()
            self.data[key] = item
            return item

    def __delitem__(self,key):
        del self.data[key]

    def addShowComment(self,id):
        if not id in self.showcomments:
            self.showcomments.append(id)
    def removeShowComment(self,id):
        try:
            self.showcomments.remove(id)
        except ValueError:
            pass
    def showComment(self,id):
        return id in self.showcomments

    def _optionsFromArgs(self,args):
        for key in self.options.keys():
            if args.has_key(key):
                value = args[key][0]
                try:
                    value = int(value)
                    if value:
                        self.options[key] = True
                    else:
                        self.options[key] = False
                    del args[key]
                except ValueError:
                    pass
                
    def option(self,name):
        try:
            return self.options[name]
        except:
            pass
        return None
    def setOption(self,name,value):
        self.options[name] = value

    def formatTime(self,tup):
        return time.strftime('%A, %B %d %Y %H:%M',tup)

    def isAnonymous(self):
        return self._person is None
    def username(self):
        if self._person:
            return self._person.username()
        return 'anonymous'
    def canAdmin(self):
        if not self._person:
            return False
        return self._person.isAdministrator()
    def canCreateMedia(self):
        if self.isAnonymous():
            return False
        return self._person.isModerator()
    def canModerate(self,object):
        if self.isAnonymous():
            return False
        return self._person.isModerator()
    def canComment(self,object):
        if self.isAnonymous():
            return False
        if object.creator() is self.person():
            return True
        return self.person().isCommentator()
    def canEdit(self,object):
        if not object:
            return False
        if self.isAnonymous():
            return False
        if self.person().isAdministrator():
            return True
        if self.person() == object.creator():
            return True
        return False
    def timezone(self):
        return 'MST'
    def person(self):
        if self.isAnonymous():
            return None
        return self._person

def createFactory():
    realm = ActivistRealm(activist.web.resource.Root())

    activistportal = portal.Portal(realm)
    activistportal.registerChecker(checkers.AllowAnonymousAccess(), credentials.IAnonymous)
    activistportal.registerChecker(Users)

    rez = guard.SessionWrapper(activistportal,mindFactory=ActivistMind)
    return ActivistHTTPFactory(resource=rez)

from activist import iactivist
class ActivistPath:
    interface.implements(iactivist.IActivistPath)
    def __init__(self,original):
        self.original = original
    def activistpath(self):
        if not hasattr(self.original,"_activistpath"):
            path = self.original.path
            segments = path.split('/')[1:]
            if segments[0] == 'user' and len(segments) == 2:
                username = segments[1]
                if Users.has_key(username):
                    path = '/person/' + Users[username][1]
            newpath = DataStore.translatePathViaAliases(path)
            while newpath:
                path = newpath
                newpath = DataStore.translatePathViaAliases(path)
            self.original._activistpath = path
        return self.original._activistpath
    
compy.registerAdapter(ActivistPath,nevow.context.PageContext,iactivist.IActivistPath)

class ActivistHTTPFactory(appserver.NevowSite):
    def __init__(self,resource):
        appserver.NevowSite.__init__(self,resource=resource,logPath='access_log')
        self._ipMunger = {}
        for x in range(256):
            self._ipMunger[x] = random.randint(0,256)

    def getPageContextForRequestContext(self, ctx):
        """Retrieve a resource from this site for a particular request. The
        resource will be wrapped in a PageContext which keeps track
        of how the resource was located.
        """
        path = inevow.IRemainingSegments(ctx)
        res = inevow.IResource(self.resource)
        pageContext = context.PageContext(tag=res, parent=ctx)
        return defer.maybeDeferred(res.locateChild, pageContext, path).addCallback(
            self.handleSegment, ctx.tag, path, pageContext
        )

    def mungifyIP(self,ip):
        rtn = []
        for field in ip.split('.'):
            rtn.append( str(self._ipMunger[int(field)]) )
        return '.'.join(rtn)
        

    def log(self, request):
        """
        override base; this will log munged client IP addresses instead
        of the real ones.
        """

        line = '%s - - %s "%s" %d %s "%s" "%s"\n' % (
            Config.munge_ip_logging and self.mungifyIP(request.getClientIP()) or request.getClientIP(),
            # request.getUser() or "-", # the remote user is almost never important
            datetimeToLogString(),
            '%s %s %s' % (request.method, request.uri, request.clientproto),
            request.code,
            request.sentLength or "-",
            request.getHeader("referer") or "-",
            request.getHeader("user-agent") or "-")
        self.logFile.write(line)
    
    
